package com.sensetime.jv.service.impl;

import com.alibaba.nacos.shaded.com.google.common.collect.Sets;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.sensetime.jv.entity.PermissionsJv;
import com.sensetime.jv.entity.RolePermissionsJv;
import com.sensetime.jv.entity.RolesJv;
import com.sensetime.jv.entity.UserRolesJv;
import com.sensetime.jv.mapper.PermissionsMapper;
import com.sensetime.jv.mapper.RolePermissionsMapper;
import com.sensetime.jv.mapper.RolesMapper;
import com.sensetime.jv.mapper.UserRolesMapper;
import com.sensetime.jv.service.RoleService;
import com.sensetime.jv.service.UrlPermissionService;
import com.sensetime.jv.service.UserRoleCacheService;
import com.sensetime.jv.util.AssertUtil;
import com.sensetime.jv.vo.RoleRespVO;
import com.sensetime.jv.vo.RoleSaveReqVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class RoleServiceImpl implements RoleService {

    private final RolesMapper rolesMapper;
    private final RolePermissionsMapper rolePermissionsMapper;
    private final PermissionsMapper permissionsMapper;
    private final UserRolesMapper userRolesMapper;
    private final UrlPermissionService urlPermissionService;

    private final UserRoleCacheService userRoleCacheService;

    @Override
    public List<RoleRespVO> listAll() {
        List<RolesJv> roles = rolesMapper.selectList(null);
        return roles.stream()
                    .map(this::fillPermissions)
                    .collect(Collectors.toList());
    }

    @Override
    public RoleRespVO detail(Integer id) {
        RolesJv role = rolesMapper.selectById(id);
        AssertUtil.notNull(role, "角色不存在");
        return fillPermissions(role);
    }




    @Override
    @Transactional
    public void saveOrUpdate(RoleSaveReqVO vo) {
        // 1. 保存角色
        RolesJv role = new RolesJv();
        role.setId(vo.getId());
        role.setRoleName(vo.getRoleName());

        List<RolesJv> list = new LambdaQueryChainWrapper<>(rolesMapper).eq(RolesJv::getRoleName, vo.getRoleName()).list();
        boolean match = list.stream().allMatch(item -> item.getId().equals(vo.getId()) && vo.getRoleName().equals(item.getRoleName()));
        AssertUtil.isTrue(match, "角色名称重复");
        if (vo.getId() == null) {
            rolesMapper.insert(role);
        } else {
            // 查看这个role是否存在
            RolesJv oldRole = rolesMapper.selectById(vo.getId());
            AssertUtil.notNull(oldRole, "角色不存在");
            rolesMapper.updateById(role);

        }

        // 2. 删除旧权限
        rolePermissionsMapper.delete(
                Wrappers.<RolePermissionsJv>lambdaQuery()
                        .eq(RolePermissionsJv::getRoleId, role.getId()));

        // 3. 过滤无效 permissionId
        Set<Integer> validPermissionIds = Optional.ofNullable(
                        permissionsMapper.selectBatchIds(vo.getPermissionIds()))
                .orElse(Collections.emptyList())
                .stream()
                .map(PermissionsJv::getId)
                .collect(Collectors.toSet());
        AssertUtil.isTrue(validPermissionIds.size()== Sets.newHashSet(vo.getPermissionIds()).size(), "参数包含无效的权限，请检查");

        // 4. 插入新权限
        List<RolePermissionsJv> batch = validPermissionIds.stream()
                .map(pid -> new RolePermissionsJv(role.getId(), pid))
                .collect(Collectors.toList());
        if (!batch.isEmpty()) {
            rolePermissionsMapper.insertBatchSomeColumn(batch);
        }
        if (vo.getId() != null){
            userRoleCacheService.updateUserRole(vo.getId());
        }
        urlPermissionService.removeAll();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeById(Integer id) {

        RolesJv rolesJv = rolesMapper.selectById(id);
        AssertUtil.notNull(rolesJv,"当前角色不存在");
        // 判断是否有用户绑定该角色，如果绑定，则不可删除
        List<UserRolesJv> userRolesJvList = userRolesMapper.selectList(
                Wrappers.<UserRolesJv>lambdaQuery().eq(UserRolesJv::getRoleId, id));
        AssertUtil.isTrue(userRolesJvList.isEmpty(), "当前角色已被用户绑定，不可删除");
        // 级联删除中间表
        rolePermissionsMapper.delete(
                Wrappers.<RolePermissionsJv>lambdaQuery()
                        .eq(RolePermissionsJv::getRoleId, id));
        rolesMapper.deleteById(id);
        userRoleCacheService.updateUserRole(id);
        urlPermissionService.removeAll();
    }

    /* ------------ 私有工具方法 ------------ */
    private RoleRespVO fillPermissions(RolesJv role) {
        RoleRespVO vo = new RoleRespVO();
        vo.setId(role.getId());
        vo.setRoleName(role.getRoleName());

        List<Integer> pIds = rolePermissionsMapper.selectList(
                Wrappers.<RolePermissionsJv>lambdaQuery()
                        .select(RolePermissionsJv::getPermissionId)
                        .eq(RolePermissionsJv::getRoleId, role.getId()))
                .stream()
                .map(RolePermissionsJv::getPermissionId)
                .collect(Collectors.toList());

        if (!pIds.isEmpty()) {
            vo.setPermissions(permissionsMapper.selectByIds(pIds));
        } else {
            vo.setPermissions(Collections.emptyList());
        }
        return vo;
    }
}